import './index.scss';
import { GUI } from 'three/examples/jsm/libs/lil-gui.module.min.js';
import { BaseThree, getProjection } from './plugin';
import * as turf from '@turf/turf';
import boundData from './examples/assets/富平县边界.json';
import zoneData from './examples/assets/富平县.json';
import pipeData from './examples/assets/富平县管线.json';
import Floor from './examples/Floor';
import Floor2 from './examples/Floor2';
import Zone from './examples/Zone';
import Point from './examples/Point';
import Site from './examples/Site';

let threeIns = null;
const setting = {
  mount,
  unmount,
  cameraPosition: delegatingHandler(() => {
    window.alert(threeIns.camera.position.toArray().join());
  }),
  pipe: false,
  point: true,
  site: false,
  popup: true,
};
let GB = {};

function init() {
  initGUI();
  initData();

  mount();
}

function delegatingHandler(fn) {
  return () => {
    if (threeIns) {
      fn();
    } else {
      console.warn('three实例不存在');
    }
  };
}

function initGUI() {
  const gui = new GUI({ title: '控制面板' });

  const folder1 = gui.addFolder('生命周期');
  folder1.add(setting, 'mount').name('挂载');
  folder1.add(setting, 'unmount').name('卸载');

  const folder2 = gui.addFolder('属性');
  folder2.add(setting, 'cameraPosition').name('相机位置');

  const folder3 = gui.addFolder('显示控制');
  folder3.add(setting, 'pipe').name('管线').onChange(handleModelVisible);
  folder3.add(setting, 'point').name('点位').onChange(handleModelVisible);
  folder3.add(setting, 'site').name('站点').onChange(handleModelVisible);
  folder3.add(setting, 'popup').name('站点标签').onChange(handleModelVisible);
}

function initData() {
  const projection = getProjection(boundData);

  const bound = [];

  turf.featureEach(boundData, ({ geometry }) => {
    if (geometry.type === 'Polygon') {
      geometry.coordinates.forEach((polygon) => {
        const path = polygon.map(projection);
        bound.push(path);
      });
    } else {
      geometry.coordinates.forEach((multiPolygon) => {
        multiPolygon.forEach((polygon) => {
          const path = polygon.map(projection);
          bound.push(path);
        });
      });
    }
  });

  GB.bound = bound;

  const zones = [];

  turf.featureEach(zoneData, (feature) => {
    const {
      properties: { name, adcode },
      geometry: { coordinates },
    } = feature;

    const zone = {
      id: adcode,
      name,
      center: projection(turf.getCoord(turf.center(feature))),
      polygons: [],
    };

    coordinates.forEach((multiPolygon) => {
      multiPolygon.forEach((polygon) => {
        zone.polygons.push(polygon.map(projection));
      });
    });

    zones.push(zone);
  });

  GB.zones = zones;

  const pipes = [];

  turf.featureEach(pipeData, (feature) => {
    feature.geometry.coordinates.forEach((line) => {
      const pipe = line.map(projection);
      pipes.push(pipe);
    });
  });

  GB.pipes = pipes;

  GB.sites = zones.map((v, i) => ({
    id: i + 1,
    name: v.name,
    position: [...v.center, 2],
    type: Math.random() < 0.5 ? 'sc' : 'bz',
    points: [
      { name: '瞬时流量', value: (Math.random() * 100).toFixed(2), unit: 'm³/h' },
      { name: '累计流量', value: (Math.random() * 10000).toFixed(2), unit: 'm³' },
      { name: '出口压力', value: (Math.random() * 10).toFixed(2), unit: 'MPa' },
      { name: '瞬时压力', value: (Math.random() * 10).toFixed(2), unit: 'MPa' },
    ],
  }));
}

function mount() {
  threeIns = new BaseThree('#app', {
    debug: true,
    interactive: true,
    css3DRenderer: true,
    camera: {
      position: [0, 30.134378360125805, 45.20156754018872],
    },
    axes: {
      visible: false,
    },
  });

  initLights();
  initModel();
}

function unmount() {
  if (threeIns) {
    threeIns.dispose();
    threeIns = null;
  }
}

function initLights() {
  const ambientLight = new THREE.AmbientLight(0xffffff, 1);
  threeIns.scene.add(ambientLight);

  const directionalLight = new THREE.DirectionalLight(0xffffff, 5);
  directionalLight.position.set(40, 60, 100);
  directionalLight.castShadow = true;
  threeIns.scene.add(directionalLight);

  const camera = directionalLight.shadow.camera;
  camera.near = 0;
  camera.far = 28;
  camera.top = 10;
  camera.bottom = -10;
  camera.left = -20;
  camera.right = 20;

  const directionalLight2 = directionalLight.clone();
  directionalLight2.position.set(-40, 60, -100);
  threeIns.scene.add(directionalLight2);
}

function initModel() {
  const group = new THREE.Group();
  group.rotation.x = -Math.PI / 2;

  const floor = new Floor();
  floor.object.position.z = -0.1;
  group.add(floor.object);
  threeIns.addModel(floor);
  floor.start();

  const floor2 = new Floor2();
  group.add(floor2.object);
  threeIns.addModel(floor2);
  floor2.start();

  const zone = new Zone({
    bound: GB.bound,
    zones: GB.zones,
    pipes: GB.pipes,
    wallHeight: 2,
  });
  zone.object.position.z = 0.1;
  group.add(zone.object);
  threeIns.addModel(zone);
  zone.start();

  const point = new Point({
    scale: 2,
    points: GB.zones,
  });
  point.object.position.z = 2.15;
  group.add(point.object);
  threeIns.addModel(point);
  point.start();

  zone.on('zone:mouseenter', (name) => {
    point.emit('point:active', name);
  });
  zone.on('zone:mouseleave', (name) => {
    point.emit('point:deactive', name);
  });

  const site = new Site({
    sites: GB.sites,
  });
  group.add(site.object);
  threeIns.addModel(site);
  site.start();

  threeIns.scene.add(group);

  handleModelVisible();
}

const handleModelVisible = delegatingHandler(() => {
  ['pipe', 'point', 'site', 'popup'].forEach((name) => {
    const obj = threeIns.scene.getObjectByName(name);
    if (obj) {
      obj.visible = setting[name];
    }
  });
});

init();
